package com.bacon.gmall.common.config;

import com.alibaba.fastjson.JSONObject;
import com.bacon.gmall.common.pojo.GmallCorrelationData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * @author： bacon、
 * @version： 1.0
 * @create： 2021-01-08 16:58
 * @description:
 */
@Component
@Slf4j
public class MQProducerAckConfig implements RabbitTemplate.ConfirmCallback,
        RabbitTemplate.ReturnCallback {


    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RedisTemplate redisTemplate;

    //被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行，并且只会被服务器执行一次
    @PostConstruct
    private void init() {
        this.rabbitTemplate.setConfirmCallback(this);
        this.rabbitTemplate.setReturnCallback(this);
    }

    //交换机应答实现类
    //成功与否都会应答
    //参数1：correlationData ： 消息发送相关消息
    //参数2：b 是否应答成功
    //参数3: 错误原因，成功为null ， 发送异常时，为错误原因
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        if (ack) {
            log.info("消息发送成功" + ack + "失败原因" + cause);
        } else {
            log.error("消息发送失败" + ack + "失败原因" + cause);

            //重新发送消息
            this.retrySendMessage(correlationData);
        }
    }


    //重新发送消息
    private void retrySendMessage(CorrelationData correlationData) {
        GmallCorrelationData gmallCorrelationData = (GmallCorrelationData) correlationData;

        int retryCount = gmallCorrelationData.getRetryCount();
        if (retryCount++ < 3) {
            //计数
            gmallCorrelationData.setRetryCount(retryCount);
            //缓存
            redisTemplate.opsForHash().put(
                    "rabbit:message", gmallCorrelationData.getId(), JSONObject.toJSONString(gmallCorrelationData));

            //重新发送
            rabbitTemplate.convertAndSend(gmallCorrelationData.getExchange(),
                    gmallCorrelationData.getRoutingKey(),
                    gmallCorrelationData.getMessage(),
                    gmallCorrelationData);
        } else {
            log.info("重发次数已达上限，请联络管理员" + JSONObject.toJSONString(gmallCorrelationData));
        }

    }

    //队列应答实现类
    //只有失败了才应答
    //参数1： Message :发送消息 消息头及体
    //参数2： relyCode：失败码 404
    //参数3： relyCode：失败码 404
    //参数4： exchange 交换机
    //参数5： routingKey 路由
    @Override
    public void returnedMessage(Message message, int replyCode,
                                String replyText, String exchange, String routingKey) {
        System.out.println("重新开始发送");
        String uuid = (String) message.getMessageProperties().getHeaders().get("spring_returned_message_correlation");

        String o = (String) redisTemplate.opsForHash().get("rabbit:message", uuid);
        GmallCorrelationData gmallCorrelationData = JSONObject.parseObject(o, GmallCorrelationData.class);
        if (gmallCorrelationData.isDelay()) {
            System.out.println("延迟插件的锅，不用重新发");
            return;
        }
        //重新开始发送
        this.retrySendMessage(gmallCorrelationData);
    }


}
